/**
*
*/
package querqy.antlr;
import java.util.LinkedList;
import java.util.List;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import querqy.SimpleComparableCharSequence;
import querqy.antlr.parser.QueryBaseVisitor;
import querqy.antlr.parser.QueryParser.BooleanPrefixContext;
import querqy.antlr.parser.QueryParser.BooleanQueryContext;
import querqy.antlr.parser.QueryParser.ClauseContext;
import querqy.antlr.parser.QueryParser.FieldNameContext;
import querqy.antlr.parser.QueryParser.NoopQueryContext;
import querqy.antlr.parser.QueryParser.OpAndContext;
import querqy.antlr.parser.QueryParser.OpOrContext;
import querqy.antlr.parser.QueryParser.QueryContext;
import querqy.antlr.parser.QueryParser.TermContext;
import querqy.antlr.parser.QueryParser.TermQueryContext;
import querqy.model.BooleanQuery;
import querqy.model.Clause.Occur;
import querqy.model.DisjunctionMaxQuery;
import querqy.model.Node;
import querqy.model.Query;
import querqy.model.Term;
/**
* @author rene
*
*/
public class QueryTransformerVisitor extends QueryBaseVisitor<Node> {
enum Operator {
NONE, AND, OR;
}
LinkedList<BooleanQuery> booleanQueryStack = new LinkedList<>();
LinkedList<Operator> operatorStack = new LinkedList<>();
Occur occurBuffer = Occur.SHOULD;
Query query = null;
final char[] input;
public QueryTransformerVisitor(char[] input) {
this.input = input;
}
@Override
public Node visitQuery(QueryContext ctx) {
query = new Query();
operatorStack.add(Operator.NONE);
booleanQueryStack.add(query);
super.visitQuery(ctx);
operatorStack.removeLast();
return booleanQueryStack.removeLast();
}
@Override
public Node visitClause(ClauseContext ctx) {
occurBuffer = getOccur(ctx);
Node result = super.visitClause(ctx);
occurBuffer = Occur.SHOULD;
return result;
}
@Override
public Node visitNoopQuery(NoopQueryContext ctx) {
BooleanQuery parent = booleanQueryStack.getLast();
if (parent != this.query) {
BooleanQuery bq = new BooleanQuery(parent, getOccur(), false);
parent.addClause(bq);
operatorStack.add(Operator.NONE);
booleanQueryStack.add(query);
}
super.visitNoopQuery(ctx);
if (parent != this.query) {
operatorStack.removeLast();
return booleanQueryStack.removeLast();
} else {
return parent;
}
}
Occur getOccur(ParserRuleContext ctx) {
List<BooleanPrefixContext> contexts = ctx.getRuleContexts(BooleanPrefixContext.class);
if (contexts == null || contexts.isEmpty()) {
return Occur.SHOULD;
}
String prf = contexts.get(0).getText();
if (prf.length() == 1) {
switch (prf.charAt(0)) {
case '+':
return Occur.MUST;
case '-':
return Occur.MUST_NOT;
}
}
return Occur.SHOULD;
}
@Override
public Node visitBooleanQuery(BooleanQueryContext ctx) {
Operator op = Operator.NONE;
List<OpAndContext> and = ctx.getRuleContexts(OpAndContext.class);
if (and != null && !and.isEmpty()) {
op = Operator.AND;
} else {
List<OpOrContext> or = ctx.getRuleContexts(OpOrContext.class);
if (or != null && !or.isEmpty()) {
op = Operator.OR;
}
}
BooleanQuery parent = booleanQueryStack.getLast();
BooleanQuery query = new BooleanQuery(parent, getOccur(), false);
parent.addClause(query);
operatorStack.add(op);
booleanQueryStack.add(query);
super.visitBooleanQuery(ctx);
operatorStack.removeLast();
return booleanQueryStack.removeLast();
}
Occur getOccur() {
if (occurBuffer == Occur.SHOULD && operatorStack.getLast() == Operator.AND) {
return Occur.MUST;
} else {
return occurBuffer;
}
}
@Override
public Node visitTermQuery(TermQueryContext ctx) {
BooleanQuery parent = booleanQueryStack.getLast();
DisjunctionMaxQuery dmq = new DisjunctionMaxQuery(parent, getOccur(), false);
TermContext tc = ctx.getRuleContext(TermContext.class, 0);
Token startToken = tc.getStart();
List<FieldNameContext> fieldNameContexts = ctx.getRuleContexts(FieldNameContext.class);
if (fieldNameContexts != null && !fieldNameContexts.isEmpty()) {
for (FieldNameContext fieldNameContext : fieldNameContexts) {
String fieldName = fieldNameContext.getText();
dmq.addClause(
new Term(dmq,
fieldName,
new SimpleComparableCharSequence(input, startToken.getStartIndex(), 1
+ startToken.getStopIndex() - startToken.getStartIndex())));
}
} else {
dmq.addClause(new Term(dmq, new SimpleComparableCharSequence(input, startToken.getStartIndex(), 1
+ startToken.getStopIndex() - startToken.getStartIndex())));
}
parent.addClause(dmq);
return dmq;
}
}